#include "image.h"
#include <iostream>
using namespace std;

SDL_Surface* Game_Image::ScaleSurface(const SDL_Surface* p_surface,int width){
	int height = p_surface->h * width / p_surface->w;
	return ScaleSurface(p_surface,width,height);
}

SDL_Surface* Game_Image::ScaleSurface(const SDL_Surface* p_surface,int width,int height){
	//Add by Septem. Bilinear Interpolation. 2008.12.05
	Uint32 PtAR=0,PtBR=0,PtCR=0,PtDR=0,PixelValueR=0;//源A、B、C、D四点像素R值
	Uint32 PtAG=0,PtBG=0,PtCG=0,PtDG=0,PixelValueG=0;//源A、B、C、D四点像素G值
	Uint32 PtAB=0,PtBB=0,PtCB=0,PtDB=0,PixelValueB=0;//源A、B、C、D四点像素B值
	Uint32 PtAA=0,PtBA=0,PtCA=0,PtDA=0,PixelValueA=0;
	
	register unsigned SpixelColNum=0,SpixelRowNum=0,DestCol=0,DestRow=0;
	Uint32 SpixelColAddr=0,SpixelRowAddr=0;
	Uint32 ColDelta=0,RowDelta=0,scaleV=0,scaleH=0;
	Uint32 ContribAandBR=0,ContribCandDR=0;//ContribAandBR:源A、B两点像素R的插值，其他类似
	Uint32 ContribAandBG=0,ContribCandDG=0;
	Uint32 ContribAandBB=0,ContribCandDB=0;
	Uint32 ContribAandBA=0,ContribCandDA=0;
	Uint32 SColor, DColor; //源、目的像素
	
	SDL_PixelFormat* p_format = p_surface->format;
	SDL_Surface* surface = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA,width,height,p_format->BitsPerPixel,p_format->Rmask,p_format->Gmask,p_format->Bmask,p_format->Amask);
	
	if(SDL_MUSTLOCK(surface)) {
		SDL_LockSurface(surface);
	}
	
	Uint32* _ContribTem = new Uint32[width * 4];
	int i=0;
	
	unsigned int g_src_width = p_surface->w, g_src_height = p_surface->h, g_dsn_width = width, g_dsn_height = height;
	scaleH=(g_src_width<<8)/g_dsn_width;
	scaleV=(g_src_height<<8)/g_dsn_height;
	     
	//first line
	for(DestCol=0;DestCol<g_dsn_width;DestCol++)
	{
	    SpixelColAddr=DestCol*scaleH;
	    ColDelta=SpixelColAddr&255;
	    SpixelColNum=(SpixelColAddr-ColDelta)>>8;
	    SColor = GetPixel(p_surface,SpixelColNum,SpixelRowNum);
	    PtAB=(SColor & p_format->Bmask)>>p_format->Bshift; 
	    PtAG=(SColor & p_format->Gmask)>>p_format->Gshift; 
	    PtAR=(SColor & p_format->Rmask)>>p_format->Rshift; 
	    PtAA=(SColor & p_format->Amask)>>p_format->Ashift; 
	    if((SpixelColNum+1)<g_src_width)
	    {
	        SColor = GetPixel(p_surface,SpixelColNum + 1,SpixelRowNum);
	        PtBB=(SColor & p_format->Bmask)>>p_format->Bshift; 
	        PtBG=(SColor & p_format->Gmask)>>p_format->Gshift; 
	        PtBR=(SColor & p_format->Rmask)>>p_format->Rshift;
	        PtBA=(SColor & p_format->Amask)>>p_format->Ashift; 
	                      
	        SColor = GetPixel(p_surface,SpixelColNum,SpixelRowNum + 1);
	        PtCB=(SColor & p_format->Bmask)>>p_format->Bshift; 
	        PtCG=(SColor & p_format->Gmask)>>p_format->Gshift; 
	        PtCR=(SColor & p_format->Rmask)>>p_format->Rshift; 
	        PtCA=(SColor & p_format->Amask)>>p_format->Ashift; 
	
	        SColor = GetPixel(p_surface,SpixelColNum + 1,SpixelRowNum + 1);
	        PtDB=(SColor & p_format->Bmask)>>p_format->Bshift; 
	        PtDG=(SColor & p_format->Gmask)>>p_format->Gshift; 
	        PtDR=(SColor & p_format->Rmask)>>p_format->Rshift; 
	        PtDA=(SColor & p_format->Amask)>>p_format->Ashift; 
	    }
	    else
	    {
	        PtBB=PtCB=PtDB=PtAB;
	        PtBG=PtCG=PtDG=PtAG;
	        PtBR=PtCR=PtDR=PtAR;
	        PtBA=PtCA=PtDA=PtAA;
	    }
	
	    ContribAandBB=ColDelta*(PtBB-PtAB)+PtAB*256;
	    ContribCandDB=ColDelta*(PtDB-PtCB)+PtCB*256;
	    _ContribTem[i++]=ContribCandDB;
	    PixelValueB=(ContribAandBB*256+(ContribCandDB-ContribAandBB)*RowDelta)>>16;
	    PixelValueB = (PixelValueB << p_format->Bshift) & p_format->Bmask;
	                  
	    ContribAandBG=ColDelta*(PtBG-PtAG)+PtAG*256;
	    ContribCandDG=ColDelta*(PtDG-PtCG)+PtCG*256;
	    _ContribTem[i++]=ContribCandDG;
	    PixelValueG=(ContribAandBG*256+(ContribCandDG-ContribAandBG)*RowDelta)>>16;
	    PixelValueG = (PixelValueG << p_format->Gshift) & p_format->Gmask;
	                  
	    ContribAandBR=ColDelta*(PtBR-PtAR)+PtAR*256;
	    ContribCandDR=ColDelta*(PtDR-PtCR)+PtCR*256;
	    _ContribTem[i++]=ContribCandDR;
	    PixelValueR=(ContribAandBR*256+(ContribCandDR-ContribAandBR)*RowDelta)>>16;
	    PixelValueR = (PixelValueR << p_format->Rshift) & p_format->Rmask;
	    
	    ContribAandBA=ColDelta*(PtBA-PtAA)+PtAA*256;
	    ContribCandDA=ColDelta*(PtDA-PtCA)+PtCA*256;
	    _ContribTem[i++]=ContribCandDA;
	    PixelValueA=(ContribAandBA*256+(ContribCandDA-ContribAandBA)*RowDelta)>>16;
	    PixelValueA = (PixelValueA << p_format->Ashift) & p_format->Amask; 
	
	    DColor = PixelValueR | PixelValueG | PixelValueB | PixelValueA;
	    PutPixel(surface, DestCol, DestRow, DColor);	
	}
	
	//////////other line//////////
	for(DestRow=1;DestRow< g_dsn_height;DestRow++)
	{
	    i=0;
	    SpixelRowAddr=DestRow*scaleV;
	    RowDelta=SpixelRowAddr&255;
	    SpixelRowNum=(SpixelRowAddr-RowDelta)>>8;
	            
	    for(DestCol=0;DestCol< g_dsn_width;DestCol++)
	    {
	        SpixelColAddr=DestCol*scaleH;
	        ColDelta=SpixelColAddr&255;
	        SpixelColNum=(SpixelColAddr-ColDelta)>>8;	         
	                 
	        if(((SpixelColNum+1)<g_src_width)&&((SpixelRowNum+1)<g_src_height))
	        {
	            SColor = GetPixel(p_surface,SpixelColNum,SpixelRowNum + 1);
		        PtCB=(SColor & p_format->Bmask)>>p_format->Bshift; 
		        PtCG=(SColor & p_format->Gmask)>>p_format->Gshift; 
		        PtCR=(SColor & p_format->Rmask)>>p_format->Rshift;
		        PtCA=(SColor & p_format->Amask)>>p_format->Ashift; 
	                      
	            SColor = GetPixel(p_surface,SpixelColNum + 1,SpixelRowNum + 1);
		        PtDB=(SColor & p_format->Bmask)>>p_format->Bshift; 
		        PtDG=(SColor & p_format->Gmask)>>p_format->Gshift; 
		        PtDR=(SColor & p_format->Rmask)>>p_format->Rshift;
		        PtDA=(SColor & p_format->Amask)>>p_format->Ashift; 
	        }
	        else
	        {
	        	SColor = GetPixel(p_surface,SpixelColNum,SpixelRowNum);
		        PtAB=(SColor & p_format->Bmask)>>p_format->Bshift; 
		        PtAG=(SColor & p_format->Gmask)>>p_format->Gshift; 
		        PtAR=(SColor & p_format->Rmask)>>p_format->Rshift;
		        PtAA=(SColor & p_format->Amask)>>p_format->Ashift;
	            PtBB=PtCB=PtDB=PtAB;
	            PtBG=PtCG=PtDG=PtAG;
	            PtBR=PtCR=PtDR=PtAR;
	            PtBA=PtCA=PtDA=PtAA;
	        }
	                  
	                  
	        ContribAandBB=_ContribTem[i];
	        ContribCandDB=ColDelta*(PtDB-PtCB)+PtCB*256;
	        _ContribTem[i++]=ContribCandDB;
	        PixelValueB=(ContribAandBB*256+(ContribCandDB-ContribAandBB)*RowDelta)>>16;
	        PixelValueB = (PixelValueB << p_format->Bshift) & p_format->Bmask;
	
	        ContribAandBG=_ContribTem[i];
	        ContribCandDG=ColDelta*(PtDG-PtCG)+PtCG*256;
	        _ContribTem[i++]=ContribCandDG;
	        PixelValueG=(ContribAandBG*256+(ContribCandDG-ContribAandBG)*RowDelta)>>16;
	        PixelValueG = (PixelValueG << p_format->Gshift) & p_format->Gmask;
	
	        ContribAandBR=_ContribTem[i];
	        ContribCandDR=ColDelta*(PtDR-PtCR)+PtCR*256;
	        _ContribTem[i++]=ContribCandDR;
	        PixelValueR=(ContribAandBR*256+(ContribCandDR-ContribAandBR)*RowDelta)>>16;
	        PixelValueR = (PixelValueR << p_format->Rshift) & p_format->Rmask;
	        
	        ContribAandBA=_ContribTem[i];
	        ContribCandDA=ColDelta*(PtDA-PtCA)+PtCA*256;
	        _ContribTem[i++]=ContribCandDA;
	        PixelValueA=(ContribAandBA*256+(ContribCandDA-ContribAandBA)*RowDelta)>>16;
	        PixelValueA = (PixelValueA << p_format->Ashift) & p_format->Amask;
	        
	        DColor = PixelValueR | PixelValueG | PixelValueB | PixelValueA;
	        PutPixel(surface, DestCol, DestRow, DColor);
	    }
	}
	if(SDL_MUSTLOCK(surface)) {
		SDL_UnlockSurface(surface);
	}
	delete []_ContribTem;
	
	return surface;
}
inline Uint32 Game_Image::GetPixel(const SDL_Surface *surface, int x, int y)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to retrieve */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        return *p;

    case 2:
        return *(Uint16 *)p;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
            return p[0] << 16 | p[1] << 8 | p[2];
        else
            return p[0] | p[1] << 8 | p[2] << 16;

    case 4:
        return *(Uint32 *)p;

    default:
        return 0;       /* shouldn't happen, but avoids warnings */
    }
}

inline void Game_Image::PutPixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to set */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        *p = pixel;
        break;

    case 2:
        *(Uint16 *)p = pixel;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        } else {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}